package com.zgw.fireline.design.Model;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.rowset.CachedRowSet;

import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.state.GlobalState;

import com.zgw.fireline.design.Activator;

/**
 * 与数据库底层交互接口工具
 * */
public class IDataBaseProvideHelp {
	// 在内存缓存加载的类对象,不重复加载 Database provide 类。
	private static Map<String, Class<?>> provideStore = new HashMap<String, Class<?>>();
	// 缓存加载类名称
	static IPreferenceStore localStore = Activator.getDefault()
			.getPreferenceStore();

	/**
	 * 获取sql 语句列信息
	 * */
	public static ResultSetMetaData getSetMetaData(Class<?> provide, String sql)
			throws Exception {
		Object dbProvide = getProvideInstance(provide);
		int paramCount = (Integer) ReflectionUtils.invokeMethod2(dbProvide,
				"getParameterCount", new Class[] { String.class },
				new Object[] { sql });
		Object[] params = new Object[paramCount];
		CachedRowSet result = (CachedRowSet) ReflectionUtils.invokeMethod2(
				dbProvide, "queryForSql", new Class[] { String.class,
						Object[].class }, new Object[] { sql, params });
		return result.getMetaData();
	}

	/**
	 * 获取Sql语句中的参数个数
	 * */
	public static Integer getParamCount(Class<?> provide, String sql)
			throws Exception {
		Object dbProvide = getProvideInstance(provide);
		int paramCount = (Integer) ReflectionUtils.invokeMethod2(dbProvide,
				"getParameterCount", new Class[] { String.class },
				new Object[] { sql });
		return paramCount;
	}

	/**
	 * 获取结果集
	 * 
	 * @throws Exception
	 * */
	public static CachedRowSet getRowSet(Class<?> provideClass, String sql,
			Object[] params) throws Exception {
		Object provide = getProvideInstance(provideClass);
		CachedRowSet set = (CachedRowSet) ReflectionUtils.invokeMethod2(
				provide, "queryForSql", String.class, Object[].class, sql,
				params);
		return set;
	}

	/**
	 * 保存一个系统数据源定义
	 * 
	 * @return
	 * 
	 * @throws Exception
	 * */
	public static void saveDatasetDefine(Class<?> provide, Object define)
			throws Exception {
		Object dbProvide = getProvideInstance(provide);
		ReflectionUtils.invokeMethod2(dbProvide, "saveDataset",
				define.getClass(), define);
	}

	public static void removeDatasetDefine(Class<?> provide, Object define)
			throws Exception {
		Object dbProvide = getProvideInstance(provide);
		String id = ReflectionUtils.getFieldString(define, "id");
		ReflectionUtils.invokeMethod2(dbProvide, "removeDataset", String.class,
				id);
	}

	public static List getAllDataset(Class<?> provide) throws Exception {
		Object dbProvide = getProvideInstance(provide);
		return (List) ReflectionUtils.invokeMethod2(dbProvide, "getAllDataset");
	}

	public static Object getDatasetDefine(Class<?> provide, String defineKey)
			throws Exception {
		Object dbProvide = getProvideInstance(provide);
		return ReflectionUtils.invokeMethod2(dbProvide, "getDataset",
				String.class, defineKey);
	}

	/**
	 * 新建一个数据集描述对象
	 */
	public static Object createDatasetDefine(Class<?> provide) {
		try {
			if (provideStore.containsKey(provide.getName())) {
				provide = provideStore.get(provide.getName());
			}
			return provide.getClassLoader()
					.loadClass("com.zgw.fireline.base.DatasetDefine")
					.newInstance();
		} catch (Exception e) {
			throw ReflectionUtils.propagate(e);
		}
	}

	private static Object getProvideInstance(Class<?> provide) throws Exception {
		Class<?> cla = loadProvideClass(provide.getName());
		Class<?> cla1 = GlobalState.getClassLoader().loadClass(
				"com.zgw.fireline.base.IDataBaseProvide");
		Field fie = ReflectionUtils.getFieldByName(cla, "INSTANCE");
		Method method = ReflectionUtils.getMethodByName(cla, "getInstance");
		Object obj;
		// 静段字段获取实例
		if (fie != null && ReflectionUtils.isStatic(fie)
				&& ReflectionUtils.isPublic(fie)
				&& cla1.isAssignableFrom(fie.getType())
				&& (obj = fie.get(cla)) != null) {
			return obj;
		}
		// 静态方法获取实列
		if (method != null && cla1.isAssignableFrom(method.getReturnType())
				&& Modifier.isStatic(method.getModifiers())
				&& Modifier.isPublic(method.getModifiers())
				&& (obj = method.invoke(cla)) != null) {
			return obj;
		}
		// 构造方法获取实例
		return provideStore.get(provide.getName()).newInstance();

	}

	public static void unloadProvideClass(Class<?> provide) {
		if (provideStore.containsKey(provide.getName())) {
			provideStore.remove(provide.getName());
		}
	}

	public static Class<?> loadProvideClass(String className) throws Exception {
		if (provideStore.containsKey(className)) {
			return provideStore.get(className);
		}
		Class<?> result = null;
		result = GlobalState.getClassLoader().loadClass(className);
		Class<?> cla1 = GlobalState.getClassLoader().loadClass(
				"com.zgw.fireline.base.IDataBaseProvide");
		if (!cla1.isAssignableFrom(result)) {
			throw new Exception(className
					+ "不是com.zgw.fireline.base.IDataBaseProvide的实现类");
		}
		String text = localStore.getString("Dtabase.Provide.Class");
		if (!provideStore.containsKey(className)) {
			provideStore.put(className, result);
		}
		if (!text.contains("|" + className)) {
			text += "|" + className;
			localStore.setValue("Dtabase.Provide.Class", text);
		}
		return result;
	}

	public static List<String> getProvideClassByCache() {
		String str = localStore.getString("Dtabase.Provide.Class");
		List<String> list = new ArrayList<String>();
		for (String s : str.split("\\|")) {
			if (!s.trim().equals("")) {
				list.add(s);
			}
		}
		return list;
	}

	public static Class<?> getDefaultProvideClass() throws Exception {
		String name = localStore.getDefaultString("Dtabase.Provide.Class");
		if (name != null && !name.trim().equals("")) {
			return loadProvideClass(name);
		}
		return null;
	}

	public static void setDefaultProvideClass(String className)
			throws Exception {
		loadProvideClass(className);
		localStore.setDefault("Dtabase.Provide.Class", className);
	}

	public static void unloadProvideClass(String classnName) {
		if (provideStore.containsKey(classnName)) {
			provideStore.remove(classnName);
		}
		String provideText = localStore.getString("Dtabase.Provide.Class");
		if (provideText.contains(classnName)) {
			provideText = provideText.replaceAll("\\|" + classnName, "");
			localStore.setValue("Dtabase.Provide.Class", provideText);
		}
	}
}
